import { Server } from 'socket.io';
import logger from '../utils/logger.js';
import { formatError, formatSuccess } from '../utils/helpers.js';

// 统一提取错误信息，兼容 formatError 返回结构
const extractMessage = (result, fallbackMessage) => {
  if (!result) return fallbackMessage;
  return result.message || result.error?.message || fallbackMessage;
};

class ConnectionManager {
  constructor(server, roomManager, gameEngine) {
    this.io = new Server(server, {
      cors: {
        origin: ["http://localhost:5173", "http://localhost:8080", "http://127.0.0.1:5173"],
        methods: ["GET", "POST"],
        credentials: true
      },
      transports: ['websocket', 'polling']
    });

    this.roomManager = roomManager;
    this.gameEngine = gameEngine;
    this.connections = new Map(); // socketId -> connectionInfo
    this.playerConnections = new Map(); // playerId -> socketId
    
    this.setupSocketHandlers();
    this.startHeartbeat();
    
    logger.info('WebSocket服务器初始化完成');
  }

  setupSocketHandlers() {
    this.io.on('connection', (socket) => {
      logger.info(`新连接: ${socket.id}`);
      
      this.connections.set(socket.id, {
        socket,
        playerId: null,
        roomId: null,
        connectedAt: new Date(),
        lastPing: new Date()
      });

      // 注册事件处理器
      this.registerRoomEvents(socket);
      this.registerGameEvents(socket);
      this.registerConnectionEvents(socket);
    });
  }

  registerConnectionEvents(socket) {
    // 玩家注册
    socket.on('register_player', async (data, callback) => {
      try {
        const { playerId, roomId } = data || {};
        
        if (!playerId) {
          return callback(formatError('INVALID_PLAYER', '玩家ID不能为空'));
        }

        const connection = this.connections.get(socket.id);
        if (connection) {
          connection.playerId = playerId;
          connection.roomId = roomId;
        }

        // 更新玩家连接映射
        const oldSocketId = this.playerConnections.get(playerId);
        if (oldSocketId && oldSocketId !== socket.id) {
          // 取消旧连接的超时处理
          const oldConnection = this.connections.get(oldSocketId);
          if (oldConnection && oldConnection.timeoutId) {
            clearTimeout(oldConnection.timeoutId);
            oldConnection.timeoutId = null;
          }
          
          // 断开旧连接
          const oldSocket = this.io.sockets.sockets.get(oldSocketId);
          if (oldSocket) {
            oldSocket.emit('duplicate_connection', formatError('DUPLICATE_CONNECTION', '检测到重复连接，旧连接已断开'));
            oldSocket.disconnect(true);
          }
        }

        this.playerConnections.set(playerId, socket.id);

        // 更新数据库中的socket ID和状态
        if (roomId) {
          await this.roomManager.updatePlayerStatus(playerId, 'online', socket.id);
          
          // 加入房间频道
          socket.join(roomId);
          
          // 检查游戏会话是否存在，如果存在则恢复游戏状态
          const gameState = await this.gameEngine.getGameState(roomId);
          if (gameState) {
            socket.emit('game_state_restored', formatSuccess(gameState, '游戏状态已恢复'));
          }
        }

        logger.info(`玩家注册: ${playerId} -> ${socket.id}`);
        callback(formatSuccess({ playerId, socketId: socket.id }, '注册成功'));
        
      } catch (error) {
        logger.error(`玩家注册失败: ${error.message}`);
        callback(formatError('REGISTER_FAILED', '注册失败'));
      }
    });

    // 心跳包
    socket.on('ping', (callback) => {
      const connection = this.connections.get(socket.id);
      if (connection) {
        connection.lastPing = new Date();
      }
      if (callback) {
        callback(formatSuccess({ timestamp: new Date().toISOString() }, 'pong'));
      }
    });

    // 连接断开
    socket.on('disconnect', (reason) => {
      this.handleDisconnection(socket.id, reason);
    });

    // 错误处理
    socket.on('error', (error) => {
      logger.error(`Socket错误 ${socket.id}: ${error.message}`);
    });
  }

  registerRoomEvents(socket) {
    // 创建房间
    socket.on('create_room', async (data, callback) => {
      try {
        const { roomName, playerName } = data || {};
        
        if (!roomName || !playerName) {
          return callback(formatError('INVALID_INPUT', '房间名和玩家名不能为空'));
        }

        const result = await this.roomManager.createRoom(roomName, playerName);
        
        if (result.success) {
          const { room, player } = result.data;
          
          // 更新连接信息
          const connection = this.connections.get(socket.id);
          if (connection) {
            connection.playerId = player.id;
            connection.roomId = room.id;
          }

          this.playerConnections.set(player.id, socket.id);
          
          // 加入房间频道
          socket.join(room.id);
          
          // 更新玩家在线状态
          await this.roomManager.updatePlayerStatus(player.id, 'online', socket.id);
          
          logger.info(`房间创建成功: ${room.id} by ${player.name}`);
          callback(formatSuccess({ room, player }, '房间创建成功'));
        } else {
          callback(formatError('CREATE_FAILED', extractMessage(result, '房间创建失败')));
        }
      } catch (error) {
        logger.error(`创建房间失败: ${error.message}`);
        callback(formatError('SERVER_ERROR', '服务器内部错误'));
      }
    });

    // 加入房间
    socket.on('join_room', async (data, callback) => {
      try {
        const { roomId, playerName } = data || {};
        
        if (!roomId || !playerName) {
          return callback(formatError('INVALID_INPUT', '房间ID和玩家名不能为空'));
        }

        const result = await this.roomManager.joinRoom(roomId, playerName);
        
        if (result.success) {
          const { room, player } = result.data;
          
          // 更新连接信息
          const connection = this.connections.get(socket.id);
          if (connection) {
            connection.playerId = player.id;
            connection.roomId = room.id;
          }

          this.playerConnections.set(player.id, socket.id);
          
          // 加入房间频道
          socket.join(room.id);
          
          // 更新玩家在线状态
          await this.roomManager.updatePlayerStatus(player.id, 'online', socket.id);
          
          // 通知房间内其他玩家
          socket.to(room.id).emit('player_joined', formatSuccess({
            player: { 
              id: player.id, 
              name: player.name, 
              seatIndex: player.seatIndex 
            },
            room
          }, `${player.name} 加入了房间`));
          
          logger.info(`玩家加入房间: ${player.name} -> ${room.id}`);
          callback(formatSuccess({ room, player }, '加入房间成功'));
        } else {
          callback(formatError('JOIN_FAILED', extractMessage(result, '加入房间失败')));
        }
      } catch (error) {
        logger.error(`加入房间失败: ${error.message}`);
        callback(formatError('SERVER_ERROR', '服务器内部错误'));
      }
    });

    // 离开房间
    socket.on('leave_room', async (callback) => {
      try {
        const connection = this.connections.get(socket.id);
        if (!connection || !connection.playerId) {
          return callback(formatError('NOT_IN_ROOM', '您不在任何房间中'));
        }

        const { playerId, roomId } = connection;
        
        const result = await this.roomManager.leaveRoom(playerId);
        
        if (result.success) {
          // 离开房间频道
          socket.leave(roomId);
          
          // 清理连接信息
          connection.playerId = null;
          connection.roomId = null;
          this.playerConnections.delete(playerId);
          
          if (!result.roomDeleted && result.data?.room) {
            // 通知房间内其他玩家
            socket.to(roomId).emit('player_left', formatSuccess({
              playerId,
              room: result.data.room
            }, '玩家离开了房间'));
          }
          
          logger.info(`玩家离开房间: ${playerId} from ${roomId}`);
          callback(formatSuccess(null, '离开房间成功'));
        } else {
          callback(formatError('LEAVE_FAILED', extractMessage(result, '离开房间失败')));
        }
      } catch (error) {
        logger.error(`离开房间失败: ${error.message}`);
        callback(formatError('SERVER_ERROR', '服务器内部错误'));
      }
    });

    // 切换准备状态
    socket.on('toggle_ready', async (data, callback) => {
      try {
        const { ready } = data || {};
        const connection = this.connections.get(socket.id);
        
        if (!connection || !connection.playerId || !connection.roomId) {
          return callback(formatError('NOT_IN_ROOM', '您不在任何房间中'));
        }

        const result = await this.roomManager.toggleReady(connection.playerId, Boolean(ready));
        
        if (result.success) {
          // 通知房间内所有玩家
          this.io.to(connection.roomId).emit('room_updated', formatSuccess(
            result.data.room, 
            `玩家${ready ? '已准备' : '取消准备'}`
          ));
          
          callback(formatSuccess(null, ready ? '已准备' : '已取消准备'));
        } else {
          callback(formatError('READY_FAILED', extractMessage(result, '更新准备状态失败')));
        }
      } catch (error) {
        logger.error(`切换准备状态失败: ${error.message}`);
        callback(formatError('SERVER_ERROR', '服务器内部错误'));
      }
    });

    // 添加AI玩家
    socket.on('add_ai_player', async (callback) => {
      try {
        const connection = this.connections.get(socket.id);
        
        if (!connection || !connection.playerId || !connection.roomId) {
          return callback(formatError('NOT_IN_ROOM', '您不在任何房间中'));
        }

        const result = await this.roomManager.addAIPlayer(connection.playerId);
        
        if (result.success) {
          // 通知房间内所有玩家
          this.io.to(connection.roomId).emit('room_updated', formatSuccess(
            result.data.room, 
            `${result.data.aiPlayer.name} 加入了房间`
          ));
          
          callback(formatSuccess(result.data, 'AI玩家添加成功'));
        } else {
          callback(formatError('ADD_AI_FAILED', extractMessage(result, '添加AI玩家失败')));
        }
      } catch (error) {
        logger.error(`添加AI玩家失败: ${error.message}`);
        callback(formatError('SERVER_ERROR', '服务器内部错误'));
      }
    });

    // 开始游戏
    socket.on('start_game', async (callback) => {
      try {
        const connection = this.connections.get(socket.id);
        
        if (!connection || !connection.playerId || !connection.roomId) {
          return callback(formatError('NOT_IN_ROOM', '您不在任何房间中'));
        }

        // 防止重复请求
        if (connection.startingGame) {
          return callback(formatError('ALREADY_STARTING', '游戏正在启动中，请稍候'));
        }
        
        connection.startingGame = true;
        
        try {
          const result = await this.roomManager.startGame(connection.playerId);
          
          if (result.success) {
            const { room } = result.data;
            
            // 初始化游戏引擎
            const gameResult = await this.gameEngine.startGame(room.id, room.players);
            
            if (gameResult.success) {
              // 通知房间内所有玩家游戏开始
              this.io.to(connection.roomId).emit('game_started', formatSuccess(
                gameResult.data, 
                '游戏开始！'
              ));
              
              logger.info(`游戏开始: ${connection.roomId}`);
              callback(formatSuccess(null, '游戏开始成功'));
            } else {
              // 如果游戏引擎启动失败，回滚房间状态
              await this.roomManager.updateRoomStatus(connection.roomId, 'waiting');
              callback(formatError('GAME_START_FAILED', extractMessage(gameResult, '游戏初始化失败')));
            }
          } else {
            callback(formatError('START_FAILED', extractMessage(result, '开始游戏失败')));
          }
        } finally {
          // 清除启动标志
          connection.startingGame = false;
        }
        
      } catch (error) {
        logger.error(`开始游戏失败: ${error.message}`);
        callback(formatError('SERVER_ERROR', '服务器内部错误'));
      }
    });

    // 获取房间列表
    socket.on('get_rooms', async (callback) => {
      try {
        const rooms = await this.roomManager.getAvailableRooms(20);
        callback(formatSuccess(rooms, '获取房间列表成功'));
      } catch (error) {
        logger.error(`获取房间列表失败: ${error.message}`);
        callback(formatError('SERVER_ERROR', '服务器内部错误'));
      }
    });
  }

  registerGameEvents(socket) {
    // 出牌
    socket.on('play_cards', async (data, callback) => {
      try {
        const { cards, playerId: targetPlayerId } = data || {};
        const connection = this.connections.get(socket.id);
        
        if (!connection || !connection.playerId || !connection.roomId) {
          return callback(formatError('NOT_IN_ROOM', '您不在游戏中'));
        }

        const effectivePlayerId = targetPlayerId || connection.playerId;

        if (targetPlayerId && targetPlayerId !== connection.playerId) {
          const session = this.gameEngine.getSessionByRoomId(connection.roomId);
          const targetPlayer = session?.players.find(p => p.id === targetPlayerId);

          if (!targetPlayer) {
            return callback(formatError('PLAYER_NOT_FOUND', '玩家不存在'));
          }

          if (!targetPlayer.isAI) {
            return callback(formatError('NOT_AUTHORIZED', '不能代替真人出牌'));
          }
        }

        const result = await this.gameEngine.playCards(
          connection.roomId, 
          effectivePlayerId, 
          cards
        );
        
        if (result.success) {
          // 广播游戏状态更新
          this.io.to(connection.roomId).emit('game_state_update', formatSuccess(
            result.data, 
            '出牌成功'
          ));
          
          callback(formatSuccess(null, '出牌成功'));
        } else {
          callback(formatError('PLAY_FAILED', extractMessage(result, '出牌失败')));
        }
      } catch (error) {
        logger.error(`出牌失败: ${error.message}`);
        callback(formatError('SERVER_ERROR', '服务器内部错误'));
      }
    });

    // 扣牌
    socket.on('pass_turn', async (data, callback) => {
      try {
        const { discardCards, playerId: targetPlayerId } = data || {};
        const connection = this.connections.get(socket.id);
        
        if (!connection || !connection.playerId || !connection.roomId) {
          return callback(formatError('NOT_IN_ROOM', '您不在游戏中'));
        }

        const effectivePlayerId = targetPlayerId || connection.playerId;

        if (targetPlayerId && targetPlayerId !== connection.playerId) {
          const session = this.gameEngine.getSessionByRoomId(connection.roomId);
          const targetPlayer = session?.players.find(p => p.id === targetPlayerId);

          if (!targetPlayer) {
            return callback(formatError('PLAYER_NOT_FOUND', '玩家不存在'));
          }

          if (!targetPlayer.isAI) {
            return callback(formatError('NOT_AUTHORIZED', '不能代替真人扣牌'));
          }
        }

        const result = await this.gameEngine.passTurn(
          connection.roomId, 
          effectivePlayerId, 
          discardCards
        );
        
        if (result.success) {
          // 广播游戏状态更新
          this.io.to(connection.roomId).emit('game_state_update', formatSuccess(
            result.data, 
            '扣牌成功'
          ));
          
          callback(formatSuccess(null, '扣牌成功'));
        } else {
          callback(formatError('PASS_FAILED', extractMessage(result, '扣牌失败')));
        }
      } catch (error) {
        logger.error(`扣牌失败: ${error.message}`);
        callback(formatError('SERVER_ERROR', '服务器内部错误'));
      }
    });

    // 收牌
    socket.on('collect_cards', async (dataOrCallback, maybeCallback) => {
      const callback = typeof dataOrCallback === 'function' ? dataOrCallback : 
        (typeof maybeCallback === 'function' ? maybeCallback : null);
      try {
        const connection = this.connections.get(socket.id);
        
        if (!connection || !connection.playerId || !connection.roomId) {
          if (callback) {
            return callback(formatError('NOT_IN_ROOM', '您不在游戏中'));
          }
          logger.warn(`收牌失败: 连接信息缺失 (${socket.id})`);
          return;
        }

        const result = await this.gameEngine.collectCards(
          connection.roomId,
          connection.playerId
        );
        
        if (result.success) {
          // 广播游戏状态更新
          this.io.to(connection.roomId).emit('game_state_update', formatSuccess(
            result.data, 
            '收牌完成'
          ));
          
          callback && callback(formatSuccess(null, '收牌成功'));
        } else {
          callback && callback(formatError('COLLECT_FAILED', extractMessage(result, '收牌失败')));
        }
      } catch (error) {
        logger.error(`收牌失败: ${error.message}`);
        callback && callback(formatError('SERVER_ERROR', '服务器内部错误'));
      }
    });

    // 发起扣了
    socket.on('initiate_koule', async (callback) => {
      try {
        const connection = this.connections.get(socket.id);
        
        if (!connection || !connection.playerId || !connection.roomId) {
          return callback(formatError('NOT_IN_ROOM', '您不在游戏中'));
        }

        const result = await this.gameEngine.initiateKouLe(
          connection.roomId, 
          connection.playerId
        );
        
        if (result.success) {
          // 广播扣了发起事件
          this.io.to(connection.roomId).emit('koule_initiated', formatSuccess(
            result.data, 
            '扣了发起，请其他玩家做出决策'
          ));
          
          callback(formatSuccess(null, '扣了发起成功'));
        } else {
          callback(formatError('KOULE_FAILED', extractMessage(result, '扣了发起失败')));
        }
      } catch (error) {
        logger.error(`发起扣了失败: ${error.message}`);
        callback(formatError('SERVER_ERROR', '服务器内部错误'));
      }
    });

    // 响应扣了
    socket.on('respond_koule', async (data, callback) => {
      try {
        const { decision } = data || {}; // 'kou' or 'xuan'
        const connection = this.connections.get(socket.id);
        
        if (!connection || !connection.playerId || !connection.roomId) {
          return callback(formatError('NOT_IN_ROOM', '您不在游戏中'));
        }

        const result = await this.gameEngine.respondToKouLe(
          connection.roomId, 
          connection.playerId, 
          decision
        );
        
        if (result.success) {
          // 广播扣了响应结果
          this.io.to(connection.roomId).emit('koule_response', formatSuccess(
            result.data, 
            `玩家做出了${decision === 'kou' ? '扣了' : '宣'}的决策`
          ));
          
          callback(formatSuccess(null, '决策成功'));
        } else {
          callback(formatError('KOULE_RESPONSE_FAILED', extractMessage(result, '扣了决策失败')));
        }
      } catch (error) {
        logger.error(`响应扣了失败: ${error.message}`);
        callback(formatError('SERVER_ERROR', '服务器内部错误'));
      }
    });
  }

  handleDisconnection(socketId, reason) {
    const connection = this.connections.get(socketId);
    
    if (connection) {
      const { playerId, roomId } = connection;
      
      logger.info(`连接断开: ${socketId} (${reason})`);
      
      if (playerId && roomId) {
        // 设置玩家为离线状态
        this.roomManager.updatePlayerStatus(playerId, 'offline').catch(error => {
          logger.error(`更新玩家离线状态失败: ${error.message}`);
        });
        
        // 通知房间内其他玩家
        this.io.to(roomId).emit('player_disconnected', formatSuccess({
          playerId,
          reason,
          timestamp: new Date().toISOString()
        }, '玩家断开连接'));
        
        // 设置重连等待时间（根据断开原因调整）
        const reconnectTimeout = reason === 'transport close' ? 15000 : 30000;
        
        // 设置自动移除玩家（如果未重连）
        const timeoutId = setTimeout(async () => {
          try {
            const currentSocketId = this.playerConnections.get(playerId);
            if (!currentSocketId || !this.io.sockets.sockets.get(currentSocketId)) {
              // 玩家仍未重连，设置为断开状态
              await this.roomManager.updatePlayerStatus(playerId, 'disconnected');
              
              // 通知房间
              this.io.to(roomId).emit('player_timeout', formatSuccess({
                playerId,
                timeoutReason: 'no_reconnection',
                timestamp: new Date().toISOString()
              }, '玩家连接超时'));
              
              logger.info(`玩家连接超时: ${playerId}`);
            }
          } catch (error) {
            logger.error(`处理玩家超时失败: ${error.message}`);
          }
        }, reconnectTimeout);
        
        // 保存超时ID，以便重连时取消
        connection.timeoutId = timeoutId;
      }
      
      // 清理连接记录
      this.connections.delete(socketId);
      if (playerId) {
        const currentSocketId = this.playerConnections.get(playerId);
        if (currentSocketId === socketId) {
          this.playerConnections.delete(playerId);
        }
      }
    }
  }

  // 心跳检测
  startHeartbeat() {
    // 定期发送心跳给所有连接的客户端
    this.heartbeatInterval = setInterval(() => {
      const activeSockets = Array.from(this.connections.keys());
      
      activeSockets.forEach(socketId => {
        const socket = this.io.sockets.sockets.get(socketId);
        if (socket && socket.connected) {
          socket.emit('heartbeat', formatSuccess({
            timestamp: new Date().toISOString(),
            connectionId: socketId
          }, '服务器心跳'));
        }
      });
    }, 30000); // 每30秒发送一次心跳

    // 检查超时连接
    this.timeoutCheckInterval = setInterval(() => {
      const now = new Date();
      const timeoutConnections = [];
      
      for (const [socketId, connection] of this.connections.entries()) {
        // 5分钟无心跳则认为连接异常
        const timeSinceLastPing = now - connection.lastPing;
        if (timeSinceLastPing > 5 * 60 * 1000) {
          timeoutConnections.push({ socketId, timeSinceLastPing });
        }
      }
      
      // 清理超时连接
      for (const { socketId, timeSinceLastPing } of timeoutConnections) {
        logger.warn(`连接超时，强制断开: ${socketId} (${Math.round(timeSinceLastPing / 1000)}秒未响应)`);
        const socket = this.io.sockets.sockets.get(socketId);
        if (socket) {
          socket.emit('connection_timeout', formatError('CONNECTION_TIMEOUT', '连接超时'));
          socket.disconnect(true);
        }
      }
      
    }, 60 * 1000); // 每分钟检查一次
  }

  // 获取连接统计
  getStats() {
    return {
      totalConnections: this.connections.size,
      totalPlayers: this.playerConnections.size,
      connectedRooms: new Set(Array.from(this.connections.values())
        .map(conn => conn.roomId)
        .filter(Boolean)).size
    };
  }

  // 广播系统消息
  broadcastSystemMessage(message, level = 'info') {
    this.io.emit('system_message', formatSuccess({
      message,
      level,
      timestamp: new Date().toISOString()
    }));
  }

  // 关闭服务器
  close() {
    // 清理定时器
    if (this.heartbeatInterval) {
      clearInterval(this.heartbeatInterval);
      this.heartbeatInterval = null;
    }
    if (this.timeoutCheckInterval) {
      clearInterval(this.timeoutCheckInterval);
      this.timeoutCheckInterval = null;
    }
    
    // 通知所有客户端服务器即将关闭
    this.broadcastSystemMessage('服务器即将关闭', 'warning');
    
    // 关闭WebSocket服务器
    this.io.close();
    logger.info('WebSocket服务器已关闭');
  }
}

export default ConnectionManager;
